﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Web.Compilation;
using org.theGecko.Utilities.MefMvc;
using System.Web.Mvc;
using System.Resources;

namespace LeMigue.TeamPortal.Base.Mvc
{
    public static class TeamPortalPlugins
    {
        /*private static */
        private static MefMvcPluginProvider _pluginProvider;
        private static AttributeMethod[] _methodsWithAttributes;
        private static IDictionary<string, ResourceManager> _gerenteRecursos = new Dictionary<string, ResourceManager>();

        internal const string Main = "Main";

        public static void Init(string pluginPath)
        {
            //var fullPluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");

            _pluginProvider = new MefMvcPluginProvider(pluginPath);
            _pluginProvider.Initialize();

            List<AttributeMethod> listaWithAttributes = new List<AttributeMethod>();

            //inicializa os atributos da main também
            listaWithAttributes.AddRange((from type in Assembly.GetCallingAssembly().GetTypes() from method in type.GetMethods() let attributes = method.GetCustomAttributes(typeof(AbstractPluginAttribute), true) where attributes != null && attributes.Length > 0 select new AttributeMethod() { Tipo = type, Method = method, Attribute = (AbstractPluginAttribute)attributes.First() }).ToList());

            //lê todos os plugins para buscar os atributos
            listaWithAttributes.AddRange((from plugin in _pluginProvider.Plugins from type in plugin.Assembly.GetTypes() from method in type.GetMethods() let attributes = method.GetCustomAttributes(typeof(AbstractPluginAttribute), true) where attributes != null && attributes.Length > 0 select new AttributeMethod() { Tipo = type, Method = method, Attribute = (AbstractPluginAttribute)attributes.First(), PathPlugin = String.Format("{0}/{1}", _pluginProvider.PluginPath, plugin.PluginName) }).ToList());

            _methodsWithAttributes = listaWithAttributes.ToArray();


            //inicializa os recursos
            ResourceManager rm = new ResourceManager(Assembly.GetCallingAssembly().GetName().Name + ".Resources.Textos", Assembly.GetCallingAssembly());
            _gerenteRecursos.Add(Main, rm);

            foreach (IPluginRegistration plugin in Plugins)
            {
                rm = new ResourceManager(plugin.AssemblyName + ".Resources.Textos", plugin.Assembly);
                _gerenteRecursos.Add(plugin.PluginName, rm);
            }

            InicializaAtributos();

            

        }

        private static void InicializaAtributos()
        {

           
            foreach (AttributeMethod methodAttribute in _methodsWithAttributes)
            {
                //inicializa os atributos
                ((AbstractPluginAttribute)methodAttribute.Attribute).Controller = methodAttribute.Tipo.Name.Replace("Controller", "");
                ((AbstractPluginAttribute)methodAttribute.Attribute).Action = methodAttribute.Method.Name;
                ((AbstractPluginAttribute)methodAttribute.Attribute).PathPlugin= methodAttribute.PathPlugin;
                ((AbstractPluginAttribute)methodAttribute.Attribute).Tipo = methodAttribute.Tipo;
                ((AbstractPluginAttribute)methodAttribute.Attribute).Ini();


            }
        }
        public static TPlugin[] ConteinerPlugin<TPlugin>() where TPlugin : AbstractPluginAttribute
        {

            return _methodsWithAttributes.Where(m => m.Attribute.GetType() == typeof(TPlugin)).Select(a => (TPlugin)a.Attribute).ToArray();

        }

        internal static ISet<IPluginRegistration> Plugins
        {
            get
            {
                return _pluginProvider.Plugins;
            }
        }

        public static string PluginPath
        {
            get
            {
                return _pluginProvider.PluginPath;
            }
        }
        internal static IDictionary<string, ResourceManager> GerenteRecursos
        {
            get { return _gerenteRecursos; }
        }

        internal static string PluginNameByAssembly(Assembly assembly)
        {
            return PluginNameByAssembly(assembly.GetName().Name);
        }
        internal static string PluginNameByAssembly(String assembly)
        {
            IPluginRegistration plugin = Plugins.SingleOrDefault(p => p.AssemblyName == assembly);
            if (plugin == null)
                return null;

            return plugin.PluginName;
        }

        private class AttributeMethod
        {
            internal Type Tipo;
            internal MethodInfo Method;
            internal Attribute Attribute;
            internal string PathPlugin;
        }
    }
}